package com.zxjbyte.yiyi.framework.common.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.google.common.collect.Maps;
import com.zxjbyte.yiyi.framework.common.constant.Constant;
import com.zxjbyte.yiyi.framework.common.constant.StringPool;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static com.zxjbyte.yiyi.framework.common.constant.StringPool.*;

/**
 * 扩展 cn.hutool.extra.servlet.ServletUtil
 * @Author zhangxingjia
 * @Date 2023/3/10 16:42
 * @Version: 1.0
 */
@UtilityClass
public class ServletXUtil extends ServletUtil {

    /**
     * 获取URL后面的参数转Map
     * @param url
     * @return
     */
    public Map<String, List<String>> getParamsFromUrl(String url) {
        Map<String, List<String>> map = null;
        if (url != null && url.contains(QUESTION_MARK)) {
            map = queryStringToMap(StrUtil.subAfter(url, QUESTION_MARK, false));
        }
        return map == null ? Maps.newHashMap() : map;
    }

    /**
     * URL ? 后面参数转Map
     * @param queryString
     * @return
     */
    public Map<String, List<String>> queryStringToMap(String queryString) {
        if (StrUtil.isBlank(queryString)) {
            return null;
        }
        queryString = URLUtil.decode(queryString, Constant.CHARSET_UTF_8);
        Map<String, List<String>> map = Maps.newLinkedHashMap();
        List<String> params = StrUtil.splitTrim(queryString, AMPERSAND);
        for (String param : params) {
            String[] kv = param.split(EQUALS);
            map.computeIfAbsent(kv[0], func -> new ArrayList<>()).add(kv[1]);
        }
        return map;
    }

    /**
     * 获取form表单提交的参数值
     * @param name
     * @return
     */
    public String getParameter(String name){
        return getParameter(name, null);
    }

    /**
     * 获取form表单提交的参数值
     * @param name
     * @param defaultValue
     * @return
     */
    public String getParameter(String name, String defaultValue){
        HttpServletRequest request = getRequest();
        if(request != null){
            return StrUtil.nullToDefault(request.getParameter(name), defaultValue);
        }
        return defaultValue;
    }

    /**
     * 获取 HttpServletRequest
     *
     * @return {HttpServletRequest}
     */
    public HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return (requestAttributes == null) ? null : ((ServletRequestAttributes) requestAttributes).getRequest();
    }

    /**
     * 获取 HttpServletResponse
     *
     * @return {HttpServletResponse}
     */
    public HttpServletResponse getResponse() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return (requestAttributes == null) ? null : ((ServletRequestAttributes) requestAttributes).getResponse();
    }

    /**
     * 获取浏览器UA
     * @param request 请求
     * @return ua
     */
    public String getUserAgent(HttpServletRequest request) {
        return getHeaderIgnoreCase(request, HttpHeaders.USER_AGENT);
    }

    /**
     * 是否为JSON格式请求
     * @param request
     * @return
     */
    public boolean isJsonRequest(ServletRequest request) {
        return isJsonMime(request.getContentType());
    }

    /**
     * JSON MIME examples:
     *    application/json
     *    application/json; charset=UTF8
     *    APPLICATION/JSON
     *    application/vnd.company+json
     *    "* / *" is also default to JSON
     * @param contentType
     * @return
     */
    public boolean isJsonMime(String contentType) {
        String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$";
        return contentType != null && (contentType.matches(jsonMime) || contentType.equals("*/*"));
    }

    /**
     * 输出附件
     * @param response
     * @param filename 文件名
     * @param content 附件内容
     */
    @SneakyThrows
    public void writeAttachment(HttpServletResponse response, String filename, byte[] content){
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + URLEncodeUtil.encode(filename));
        response.setContentType(FileUtil.getMimeType(filename));
        response.setContentLength(content.length);
        response.setCharacterEncoding(Constant.UTF_8);
        // 输出附件
        IoUtil.write(response.getOutputStream(), false, content);
    }

    /**
     * 获取 request 请求内容
     *
     * @param request request
     * @return {String}
     */
    public String getRequestContent(HttpServletRequest request) {
        try {
            //HttpServletRequest的getQueryString方法返回请求的查询字符串（即URL中？后面的部分）
            String queryString = request.getQueryString();
            if (StrUtil.isNotBlank(queryString)) {
                return new String(queryString.getBytes(Constant.CHARSET_ISO_8859_1), Constant.CHARSET_UTF_8)
                        .replaceAll(StringPool.HTML_AMPERSAND, StringPool.AMPERSAND).replaceAll(StringPool.ASCII_DOUBLE_QUOTES, "\"");
            }
            String charEncoding = request.getCharacterEncoding();
            if (charEncoding == null) {
                charEncoding = Constant.UTF_8;
            }
            byte[] buffer = getBodyBytes(request);
            String str = new String(buffer, charEncoding).trim();
            if(ServletXUtil.isJsonRequest(request)){
                str = JsonUtil.jsonStrCompact(str);
            }
            if (StrUtil.isBlank(str)) {
                StringBuilder buf = new StringBuilder();
                Enumeration<String> parameterNames = request.getParameterNames();
                while (parameterNames.hasMoreElements()) {
                    String key = parameterNames.nextElement();
                    String value = request.getParameter(key);
                    buf.append(key).append(StringPool.EQUALS).append(value).append(StringPool.AMPERSAND);
                }
                str = StrUtil.removeSuffix(buf.toString(), StringPool.AMPERSAND);
            }
            return str.replaceAll(StringPool.HTML_AMPERSAND, StringPool.AMPERSAND);
        } catch (Exception ex) {
            ex.printStackTrace();
            return StringPool.EMPTY;
        }
    }
}
